#include "SamplesEntity.h"
#include "RasterLayer.h"
#include <fstream>
#include <gdal/ogrsf_frmts.h>
#include <gdal/ogr_api.h>
#include <QFile>

CSamplesEntity::CSamplesEntity(void)
        :j_fTrainingRate(0.65f)
        ,j_csInputDataPath(("E:/test/test/LC81300452013165LGN00_atm.bsq"))
        ,j_nClassifyId(("1"))
        ,j_bOutShpTag(false)
		,pRasterLayer(nullptr)
        ,j_csOutputDir(("E:\\test\\"))
        ,j_csInputShpPath(("E:\\test\\water\\water.shp"))
{
}


CSamplesEntity::~CSamplesEntity(void)
{
	if(nullptr != pRasterLayer){
		delete pRasterLayer;
		pRasterLayer = nullptr;
	}
}
QString CSamplesEntity::getShpName()
{
	QString tmpFileName = this->j_csInputShpPath;
	tmpFileName.replace('\\','/');
	int tmpIndex = tmpFileName.lastIndexOf('/');
	QString fileDir = tmpFileName.mid(0, tmpIndex + 1);
	QString fName = tmpFileName.mid(tmpIndex + 1, tmpFileName.length() - tmpIndex - 1);
	return fName;
}
bool CSamplesEntity::FileExist(QString FileName)
{
	return QFile::exists(FileName);
}

void CSamplesEntity::deleteShpFiles(QString csShpFileName)
{
	QString tmpPreFileName = this->j_csOutputDir + csShpFileName;
	tmpPreFileName.replace('\\','/');
	if (FileExist(tmpPreFileName+(".shp")))
	{
		QFile::remove((tmpPreFileName+(".shp")));
	}
	if (FileExist(tmpPreFileName+(".shx")))
	{
		QFile::remove((tmpPreFileName+(".shx")));
	}
	if (FileExist(tmpPreFileName+(".dbf")))
	{
		QFile::remove((tmpPreFileName+(".dbf")));
	}

}

bool CSamplesEntity::initByData()
{
	this->j_csInputShpPath.replace('\\','/');
	if(this->pRasterLayer == nullptr){
		this->pRasterLayer = new RasterLayer(this->j_csInputDataPath);
	}
	return true;
}

string CSamplesEntity::cs2string(QString cstr)
{
   return cstr.toStdString();
}

bool CSamplesEntity::processFiles(bool bInitialedTag, vector<int> &fieldsVector, ClassType classType)
{
	if(!bInitialedTag){
		if(this->initByData() == false){
			return false;
		}
	}
	if (nullptr == this->pRasterLayer)
	{
		return false;
	}
	typedef unsigned char byte;

	// OGRSFDriverH *poDriver;
	OGRRegisterAll();

	OGRSFDriver* poDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName("ESRI Shapefile");
	OGRDataSource* poDS = poDriver->Open((const char*)(this->j_csInputShpPath.toStdString().c_str()), NULL);//数据地址
	// OGRDataSource* poDS = poDriver->Open("E:\\tt.shp", NULL );//数据地址
	OGRLayer* poLayer = poDS->GetLayer(0);

	int nFeatureCount = poLayer->GetFeatureCount();

	//FID随机数组
	vector<bool> tagVec(nFeatureCount, false);
	int nTrainingCount = (int)(nFeatureCount * this->j_fTrainingRate);
	long tmpId, curCount = 0;
	srand((unsigned)time(NULL));//用当前时间，设置随机种子   
	while (curCount < nTrainingCount)
	{
		long r1 = rand();
		long r2 = rand();
		tmpId = (r1 *10000 + r2) % nFeatureCount;
		if (tagVec[tmpId] == false)
		{
			tagVec[tmpId] = true;
			curCount++;
		}
	}
	
	if (this->j_bOutShpTag)
	{
		QString csShpFileName = this->getShpName();
		this->deleteShpFiles(csShpFileName);
		
		int tmpIndex3 = csShpFileName.indexOf('.');
		csShpFileName = csShpFileName.mid(0, tmpIndex3);
		
		QString tmpPreFileName = this->j_csOutputDir + ("/") + csShpFileName;
		
		OGRDataSource *poDSTraining = poDriver->CreateDataSource((const char*)(tmpPreFileName+("_training_out.shp")).toStdString().c_str(), NULL ); 
		OGRLayer *poLayerTraining = poDSTraining->CreateLayer("training_out", NULL, wkbPolygon, NULL );
		OGRDataSource *poDSTesting = poDriver->CreateDataSource((const char*)(tmpPreFileName+("_testing_out.shp")).toStdString().c_str(), NULL ); 
		OGRLayer *poLayerTesting = poDSTesting->CreateLayer("testing_out", NULL, wkbPolygon, NULL );
		OGRFeature *pFeatureTmp=NULL;
		int ttt =0, ttt2 = 0;
		for (int i = 0; i < nFeatureCount; i++){
			pFeatureTmp = poLayer->GetFeature(i);
			if (pFeatureTmp == NULL)
				continue;
			if (tagVec[i] == false){
				//int ttt = poLayerTesting->GetFeatureCount();
				pFeatureTmp->SetFID(ttt++);
				poLayerTesting->SetFeature(pFeatureTmp);
			}
			else{
				//int ttt2 = poLayerTraining->GetFeatureCount();
				pFeatureTmp->SetFID(ttt2++);
				poLayerTraining->SetFeature(pFeatureTmp);
			}
			delete pFeatureTmp;
		}
		OGRDataSource::DestroyDataSource( poDSTraining );
		OGRDataSource::DestroyDataSource( poDSTesting );
		
	}

	QString strCid = (this->j_nClassifyId);
	ofstream outfile_training((const char*)(this->j_csOutputDir + ("/training_samples.data")).toStdString().c_str(), ios::out|ios::app);
	ofstream outfile_testing((const char*)(this->j_csOutputDir + ("/testing_samples.data")).toStdString().c_str(), ios::out|ios::app);

	QFile DataFile(j_csInputDataPath);
	DataFile.open(QIODevice::ReadOnly);


	long bandSize =  this->pRasterLayer->getPixelCountPerBand();
	//long hdrTag = bsqHdrObj.j_nDataType;
	int i = 0;
	long long pastSize;
	OGRFeature *pFeature=NULL;

	RasterLayer::Envelope tmpEnv = this->pRasterLayer->getEnvelope();

	int j_nBands = this->pRasterLayer->getBandCount();
	double j_fMaxXCoord = tmpEnv.getMaxX();
	double j_fMinXCoord = tmpEnv.getMinX();
	double j_fMinYCoord = tmpEnv.getMinY();
	double j_fMaxYCoord = tmpEnv.getMaxY();

	double j_fXRes = this->pRasterLayer->getXResolution();
	double j_fYRes = this->pRasterLayer->getYResolution();

	//short int resDat[1];
	//byte resDat[1];

	for (i = 0; i < nFeatureCount; i++)
	{
		pFeature = poLayer->GetFeature(i);
		if (pFeature == NULL)
			continue;

		OGRGeometry *pGeometry=NULL;
		pGeometry=pFeature->GetGeometryRef();
		OGRwkbGeometryType geotype;
		geotype=pGeometry->getGeometryType();
		if (wkbPolygon!=geotype){
			OGRFeature::DestroyFeature( pFeature );
			break;
		}
		OGRPolygon *pPolygon;
		pPolygon=(OGRPolygon*)pGeometry;

		OGREnvelope* pExt;
		pExt = new OGREnvelope();
		pPolygon->getEnvelope(pExt);
		
		//modify Extent
		pExt->MinX = floor((pExt->MinX - j_fMinXCoord) / j_fXRes) * j_fXRes + j_fMinXCoord;
		pExt->MaxX = ceil((pExt->MaxX - j_fMinXCoord) / j_fXRes) * j_fXRes + j_fMinXCoord;
		
		pExt->MinY = j_fMaxYCoord - ceil((j_fMaxYCoord - pExt->MinY) / j_fYRes) * j_fYRes;
		pExt->MaxY = j_fMaxYCoord - floor((j_fMaxYCoord - pExt->MaxY) / j_fYRes) * j_fYRes;
	
		OGRPoint pt;
		OGRPoint pt1;
		OGRPoint pt2;
		OGRPoint pt3;
		for (double xIndex = pExt->MinX; xIndex <= pExt->MaxX; xIndex += j_fXRes)
		{
			for (double yIndex = pExt->MaxY; yIndex >= pExt->MinY; yIndex-= j_fYRes)
			{
				pt.setX(xIndex);
				pt.setY(yIndex);
				
				pt1.setX(xIndex + j_fXRes);
				pt1.setY(yIndex);
				
				pt2.setX(xIndex);
				pt2.setY(yIndex - j_fYRes);

				pt3.setX(xIndex + j_fXRes);
				pt3.setY(yIndex - j_fYRes);

				if(pPolygon->Contains(&pt) || pPolygon->Contains(&pt1) || pPolygon->Contains(&pt2) || pPolygon->Contains(&pt3))
				{
					std::vector<std::pair<QString, QString>> contents;
				
				/*	if (tagVec[i] == false){
						outfile_testing << strCid;
					}
					else{
						outfile_training << strCid;
					}*/
					for (int curBand =0; curBand < fieldsVector.size(); curBand++)
					{
						auto tmpPixelValue = this->pRasterLayer->getBandPixelValue(xIndex, yIndex,fieldsVector[curBand] + 1); 
						QString strBand = QString::number(fieldsVector[curBand] + 1);
						QString content = tmpPixelValue;
						contents.push_back(std::make_pair(strBand, content));

						/*if (tagVec[i] == false){
							outfile_testing <<"  "<< (fieldsVector[curBand] + 1)<<":" << tmpPixelValue.toStdString();
						}
						else{
							outfile_training<<"  "<< (fieldsVector[curBand] + 1)<<":" << tmpPixelValue.toStdString();
						}*/
					}
					//for(int curBand = 0; curBand < j_nBands; curBand++)
					//{
					//	//todo
					//	auto tmpPixelValue = this->pRasterLayer->getBandPixelValue(xIndex, yIndex,curBand + 1);
					//	if (tagVec[i] == false){
					//		outfile_testing <<"  "<< (curBand+1)<<":" << tmpPixelValue.toStdString();
					//	}
					//	else{
					//		outfile_training<<"  "<< (curBand+1)<<":" << tmpPixelValue.toStdString();
					//	}

					//}
					
					/*if (tagVec[i] == false){
					outfile_testing <<endl;
					}
					else{
					outfile_training <<endl;
					}*/

					if(classType == SVM)
					{
						QString lineContent;
						lineContent += strCid;
						for (size_t j = 0; j < contents.size(); ++j)
						{
							lineContent += "  " + contents[j].first + ":" + contents[j].second;
						}
						lineContent += "\n\r";
						if (tagVec[i] == false){
							outfile_testing << lineContent.toStdString();
						}
						else{
							outfile_training <<lineContent.toStdString();
						}
					}
					else
					{
						QString lineContent;
						for (size_t j = 0; j < contents.size(); ++j)
						{
							lineContent +=contents[j].second + ",";
						}
						lineContent += strCid + "\n\r";

						if (tagVec[i] == false){
							outfile_testing << lineContent.toStdString();
						}
						else{
							outfile_training <<lineContent.toStdString();
						}
					}
				}
			}
		}
	   
		OGRFeature::DestroyFeature(pFeature);
	}
	outfile_training.close();
	outfile_testing.close();
	DataFile.close();
	
	OGRDataSource::DestroyDataSource(poDS);
	OGRCleanupAll();
	return true;
}